#include "main.h"
#include "usbfs_cfg.h"
#include "usbfs_irq.h"
#include <sum_btimer.h>
#include <sum_csr.h>
#include <sum_eclic.h>
#include <sum_gpio.h>
#include <sum_rcu.h>
#include <sum_usart.h>
#include <sum_wfi.h>
#include <sys_mem.h>
#include <util_fifo.h>
#include <util_trans.h>

#define BUFFER_SIZE_2_POWER 14
#define BTIMER_GAP (AHB_FREQ / 4000)

// 串口输出缓冲区
static struct {
	fifo16_v fifo16;
	u8_s buffer_a[1 << BUFFER_SIZE_2_POWER];
} g_fifo16_buffer;

static volatile u32_s g_time_ms = 0;

static void _init_fifo(void) {
	fifo16_init(&(g_fifo16_buffer.fifo16), BUFFER_SIZE_2_POWER);
}

static void _init_time(void) {
	g_time_ms = 0;
}

// 设置HXTAL和PLL
static void _set_hxtal_pll(void) {
	// 开启HXTAL并等待稳定
	rcu_ctl_16_23_expl_s hxtal_setup = {
		.hxtal_en = 1,
	};
	rcu_setup_hxtal(hxtal_setup);
	do {
		hxtal_setup = rcu_read_hxtal_setup();
	} while (!hxtal_setup.is_hxtal_stable);

	// 第一次配置CFG0，仅配置输入源和分频倍数。
	rcu_cfg0_para_s cfg0_mul = {
		.pll_freq_mul = RCU_CFG0_PLL_FREQ_MUL_6,
		.pll_src = RCU_CFG0_PLL_HXTAL,
	};
	rcu_set_cfg_0(cfg0_mul);

	// 开启PLL并等待稳定
	rcu_ctl_24_31_expl_s pll_setup = {
		.pll_en = 1,
		.pll1_en = 0,
		.pll2_en = 0,
	};
	rcu_setup_pll(pll_setup);
	do {
		pll_setup = rcu_read_pll_setup();
	} while (!pll_setup.is_pll_stable);

	// 第二次配置CFG0，配置时钟源为PLL并等待稳定。
	rcu_cfg0_para_s cfg0_all = {
		.set_sys_clock = RCU_CFG0_SYS_CLOCK_PLL,
		.ahb_psc = RCU_CFG0_AHB_SYS_NO_DIV,
		.apb1_psc = RCU_CFG0_APB_AHB_NO_DIV,
		.apb2_psc = RCU_CFG0_APB_AHB_NO_DIV,
		.adc_psc = RCU_CFG0_ADC_APB2_DIV_2,
		.pll_src = RCU_CFG0_PLL_HXTAL,
		.pll_freq_mul = RCU_CFG0_PLL_FREQ_MUL_6,
		.usbfs_psc = RCU_CFG0_USBFS_PLL_NO_DIV,
		.ckout0_src = RCU_CFG0_CKOUT0_NONE,
	};
	rcu_set_cfg_0(cfg0_all);
	do {
		cfg0_all = rcu_get_cfg_0();
	} while (cfg0_all.current_sys_clock != RCU_CFG0_SYS_CLOCK_PLL);
}

// RCU中将GPIOA、USART0、USBFS上电
static void _enable_gpioa_usart0_usbfs(void) {
	rcu_apb2_s apb2 = {
		.apb2_0_7.GPIOA = 1,
		.apb2_8_15.USART0 = 1,
	};
	rcu_apb2_en_di(apb2);

	rcu_ahb_8_15_s ahb_8_15 = {
		.USBFS = 1,
	};
	rcu_ahb_8_15_en_di(ahb_8_15);
}

// 配置A9、A11、A12为AF输出，A10为浮空输入。
static void _setup_gpafio(void) {
	gpio_ctl_8_15_s ctl_8_15 = {
		// A9的配置：低速输出、AF、推挽
		.pin9_ctl = GPIO_OUT_AF_PP_2MHZ,
		// A10的配置：输入
		.pin10_ctl = GPIO_ANALOG,
		// A11的配置：最高速输出、AF、推挽
		.pin11_ctl = GPIO_OUT_AF_PP_50MHZ,
		// A12的配置：最高速输出、AF、推挽
		.pin12_ctl = GPIO_OUT_AF_PP_50MHZ,
	};
	gpio_setup_pin_8_15(GPIOA_Q, ctl_8_15);
}

// 使能USART0本身，以及其发送功能。
static void _enable_usart0_send(void) {
	usart_ctl0_expl_s ctl0 = {
		.usart_en = 1,
		.trans_en = 1,
	};
	usart_setup_0(USART0_Q, ctl0);
}

// 使能USART0发送功能、可发送中断，关闭其它。
static void _enable_send_tbe(void) {
	usart_ctl0_expl_s ctl0 = {
		.usart_en = 1,
		.trans_en = 1,
		.trans_avl_inter_en = 1,
	};
	usart_setup_0(USART0_Q, ctl0);
}

// 定时中断
static void _btimer_irq(void) {
	btimer_refresh(BTIMER_GAP);
	g_time_ms++;
}

// 串口中断
static void _usart0_irq(void) {
	usart_stat_expl_s stat = usart_get_stat(USART0_Q);
	fifo16_v* fifo16_p = &(g_fifo16_buffer.fifo16);
	if (stat.trans_avl) {
		if (fifo16_has_data(fifo16_p)) {
			u32_s byte = fifo16_out_byte(fifo16_p);
			usart_wn_byte(USART0_Q, byte);
		} else {
			_enable_usart0_send();
		}
	}
}

// 初始化串口
static void _setup_usart0(void) {
	usart_set_baud_rate(USART0_Q, 115200, APB2_FREQ);
	_enable_usart0_send();
}

// 中断配置
static void _setup_interrupt(void) {
	// 中断入口地址设为自带的中断入口
	csr_set_default_exti_entry();
	// 中断向量表
	static const __attribute__((aligned(512))) eclic_irqvec_t ivt = {
		.irq_entry_fa[IRQNO_BTIMER] = _btimer_irq,
		.irq_entry_fa[IRQNO_USART0] = _usart0_irq,
		.irq_entry_fa[IRQNO_USBFS] = usbfs_irq,
	};
	eclic_set_ivt_base(&ivt);
	// 设置中断level和priority，其中priority域占据全部bit，无level。
	eclic_cliccfg_nlbits_e nlbits = NLBITS_LEVEL_2_PRIORITY_2;
	eclic_set_level_priority_bit_amount(nlbits);

	// 定时中断
	eclic_clicint_expl_s clicint_btimer = {
		.inter_en.value = 1,
		.attr.vector_mode = 0,
		.level_priority = eclic_set_level_priority(nlbits, 3, 3),
	};
	eclic_setup_inter_expl(IRQNO_BTIMER, clicint_btimer);

	// 串口中断
	eclic_clicint_expl_s clicint_usart = {
		.inter_en.value = 1,
		.attr.vector_mode = 0,
		.level_priority = eclic_set_level_priority(nlbits, 3, 2),
	};
	eclic_setup_inter_expl(IRQNO_USART0, clicint_usart);

	// USB中断
	eclic_clicint_expl_s clicint_usbfs = {
		.inter_en.value = 1,
		.attr.vector_mode = 0,
		.level_priority = eclic_set_level_priority(nlbits, 0, 0),
	};
	eclic_setup_inter_expl(IRQNO_USBFS, clicint_usbfs);

	// 打开全局中断
	csr_enable_global_interrupt();
}

__attribute__((noreturn, section(".MAIN"))) void user_main(void) {
	mem_scatter_load();
	_set_hxtal_pll();
	_init_fifo();
	_init_time();
	_enable_gpioa_usart0_usbfs();
	_setup_gpafio();
	// 启动定时器
	btimer_start(BTIMER_GAP);
	// USART0配置
	_setup_usart0();
	// 异常入口地址直接设为0（理论上该例程中不可能发生异常）。
	csr_enable_eclic_set_entry(0);
	// 中断配置
	_setup_interrupt();
	// USBFS配置
	setup_usbfs();

	trans_write_str("Boot.\n", put_byte_to_fifo);
	wfi_loop();
}

// 向串口阻塞发送1字节的函数，也是trans_write系列函数的参数。
void put_byte_to_fifo(u32_s byte) {
#if 1
	fifo16_in_byte(&(g_fifo16_buffer.fifo16), byte);
	_enable_send_tbe();
#else
	usart_wb_byte(USART0_Q, byte);
#endif
}

// 延时
void sleep_ms(u32_s ms) {
	u32_s start_ms = g_time_ms;
	u32_s end_ms = start_ms + ms;
	while (g_time_ms < end_ms) {
		wfi();
	}
}
